/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pv1682010;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Petr
 */
public class UserManager {

    private User loggedUser = null;
    private DataSource dataSource;
    private Logger log=LoggerFactory.getLogger(UserManager.class);
    public static final String DB_USER_TABLE = "users";
    public static final String DB_USER_UCO_COLUMN = "user_uco";
    public static final String DB_USER_NAME_COLUMN = "user_name";
    public static final String DB_USER_PASSWORD_COLUMN = "user_passwordHash";
    public static final String DB_USER_ADMINISTRATOR_COLUMN = "user_administrator";

    public UserManager(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public UserManager() {
        this(null);
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        log.debug("Data Source set to {}.", dataSource);
    }

    public User getUser(int uco) {
        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = dataSource.getConnection();
            st = conn.prepareStatement("SELECT * FROM " + DB_USER_TABLE + " WHERE " + DB_USER_UCO_COLUMN + "=?");
	    st.setInt(1, uco);
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                User user = new User(rs.getInt(DB_USER_UCO_COLUMN), rs.getString(DB_USER_NAME_COLUMN), rs.getBoolean(DB_USER_ADMINISTRATOR_COLUMN));
                return user;
            }
        } catch (SQLException e) {
            log.error("Unable to get user.");
        } finally {
            DBConnection.closeQuietly(st);
            DBConnection.closeConnection(conn);
        }
	return null;
    }

    public List<User> getUsers() {
        List<User> result = new ArrayList<User>();
        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = dataSource.getConnection();
            st = conn.prepareStatement("SELECT * FROM " + DB_USER_TABLE);
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                User user = new User(rs.getInt(DB_USER_UCO_COLUMN), rs.getString(DB_USER_NAME_COLUMN), rs.getBoolean(DB_USER_ADMINISTRATOR_COLUMN));
                result.add(user);
            }
        } catch (SQLException e) {
            log.error("Unable to get list.");
        } finally {
            DBConnection.closeQuietly(st);
            DBConnection.closeConnection(conn);
        }
        return result;
    }

    public void addUser(int uco, String name, String password, boolean administrator) throws IllegalArgumentException, UserException {
        if (uco <= 0) 
            throw new IllegalArgumentException("uco must be positive number");

        if (name == null)
            throw new IllegalArgumentException("name cannot be null");

        if (password == null)
            throw new IllegalArgumentException("password cannot be null");

        PreparedStatement insertStatement = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            insertStatement = conn.prepareStatement(
                    "INSERT INTO " + DB_USER_TABLE + " (" + DB_USER_UCO_COLUMN + "," + DB_USER_NAME_COLUMN + "," + DB_USER_PASSWORD_COLUMN + "," + DB_USER_ADMINISTRATOR_COLUMN + ") VALUES (?,?,SHA1(?),?);");
            insertStatement.setInt(1, uco);
            insertStatement.setString(2, name);
            insertStatement.setString(3, password);
            insertStatement.setBoolean(4, administrator);
            insertStatement.execute();
        } catch (SQLException e) {
            log.warn("User with this uco exists {}.", uco);
            throw new UserException("User with this uco exists", e);
        } finally {
            DBConnection.closeQuietly(insertStatement);
            DBConnection.closeConnection(conn);
        }
        log.info("User added {}", uco);
    }

    public void addUser(User user, String password) throws UserException, IllegalArgumentException {
        addUser(user.getUco(), user.getName(), password, user.isAdministrator());
    }

    public boolean deleteUser(User user) throws UserException {
        PreparedStatement deleteStatement = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            deleteStatement = conn.prepareStatement(
                    "DELETE FROM " + DB_USER_TABLE + " WHERE " + DB_USER_UCO_COLUMN + " = ?;");
            deleteStatement.setInt(1, user.getUco());
            deleteStatement.execute();
            if (deleteStatement.getUpdateCount() == 1) {
                log.info("User deleted {}", user);
                return true;
            }
        } catch (SQLException e) {
            log.warn("Couldn't delete user {}", user);
            throw new UserException(e);
        } finally {
            DBConnection.closeQuietly(deleteStatement);
            DBConnection.closeConnection(conn);
        }
        log.warn("Cannot delete user {}", user);
        return false;
    }

    public boolean updateUser(User user) throws UserException {
        PreparedStatement updateStatement = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            updateStatement = conn.prepareStatement(
                    "UPDATE " + DB_USER_TABLE + " SET " + DB_USER_ADMINISTRATOR_COLUMN + "= ? , " + DB_USER_NAME_COLUMN + "= ?   WHERE " + DB_USER_UCO_COLUMN + " = ?;");
            updateStatement.setBoolean(1, user.isAdministrator());
            updateStatement.setString(2, user.getName());
            updateStatement.setInt(3, user.getUco());
            updateStatement.execute();
            if (updateStatement.getUpdateCount() == 1) {
                log.info("Updated user {}", user);
                return true;
            }
        } catch (SQLException e) {
            throw new UserException(e);
        } finally {
            DBConnection.closeQuietly(updateStatement);
            DBConnection.closeConnection(conn);
        }
        log.warn("Cannot update user {}", user);
        return false;
    }

    public boolean login(int uco, String password) throws UserException {
        PreparedStatement getUserStatement = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            getUserStatement = conn.prepareStatement(
                    "SELECT * FROM " + DB_USER_TABLE + " WHERE " + DB_USER_UCO_COLUMN + " = ? AND " + DB_USER_PASSWORD_COLUMN + " = SHA1(?) ;");
            getUserStatement.setInt(1, uco);
            getUserStatement.setString(2, password);
            ResultSet rs = getUserStatement.executeQuery();
            rs.next();
            loggedUser = new User(rs.getInt(DB_USER_UCO_COLUMN), rs.getString(DB_USER_NAME_COLUMN), rs.getBoolean(DB_USER_ADMINISTRATOR_COLUMN));
            return true;
        } catch (SQLException e) {
            log.warn("Could not log in {}", uco);
            throw new UserException("Could not log in", e);
        } finally {
            DBConnection.closeQuietly(getUserStatement);
            DBConnection.closeConnection(conn);
        }
    }

    public void logout() {
        loggedUser = null;
    }

    public User getLoggedUser() {
        return loggedUser;
    }
}
